"""
解析ND08平台xlsx
"""
import multiprocessing
import os
import json
import time

import numpy as np
import pandas as pd
from pandas import json_normalize

from 频域分析.demoPyNettest import get_cztdata_process


def read_xlsx_file(file_name):
	"""
	读取文件
	:param file_name:
	:return:
	"""
	df = pd.read_excel(file_name)
	#金标心率值 = df['金标心率'].tolist()
	json格式=df['json格式'].apply(json.loads)
	# 将解析后的 JSON 数据展平
	parsed_json_df = json_normalize(json格式)
	
	# 解析 rawData 列
	rawData_df = pd.DataFrame(parsed_json_df['rawData'].tolist(), index=parsed_json_df.index)
	rawData_df.columns = [f'rawData{i}' for i in range(rawData_df.shape[1])]
	
	# 解析 useAgcCurrent 列
	useAgcCurrent_df = pd.DataFrame(parsed_json_df['useAgcCurrent'].tolist(), index=parsed_json_df.index)
	useAgcCurrent_df.columns = [f'useAgcCurrent{i}' for i in range(useAgcCurrent_df.shape[1])]
	
	# 解析 useAgcGain 列
	useAgcGain_df = pd.DataFrame(parsed_json_df['useAgcGain'].tolist(), index=parsed_json_df.index)
	useAgcGain_df.columns = [f'useAgcGain{i}' for i in range(useAgcGain_df.shape[1])]
	
	
	
	#删除json格式列
	df = df.drop(['json格式'], axis=1)
	# 合并所有解析后的数据
	df = pd.concat(
		[df, parsed_json_df.drop(columns=['rawData', 'useAgcCurrent', 'useAgcGain']), rawData_df, useAgcCurrent_df,
		 useAgcGain_df], axis=1)
	
	# 解析timestamp 这个时间戳,再新增一列存储转换的时间,转为北京时间
	
	df['time'] = pd.to_datetime(df['timestamp'], unit='s', utc=True) \
		.dt.tz_convert('Asia/Shanghai') \
		.dt.tz_localize(None)  # 移除时区信息


	
	#print(df)
	# 导出xlsx表格
	#df.to_excel('output.xlsx', index=False)
	return df
	

def analysis_data(df):
	"""
    分析给定数据框中的数据，按照指定的窗口大小和步长，将数据分割成多个时间窗口。
    
    :param df: 包含时间戳的DataFrame，用于分析。
    :return: 一个列表，包含按照时间窗口分割的多个DataFrame。
    """
	
	# 获取更精确的时间范围（避免小数误差）
	min_time = int(df['timestamp'].min())
	max_time = int(df['timestamp'].max()) + 1
	
	sliding_windows = []
	
	# 以秒为单位滑动窗口
	window_size_sec = 10
	step_size_sec = 1
	
	# 预处理时间戳为整数（如果原始数据含小数秒）
	df['timestamp_int'] = df['timestamp'].astype(int)
	# 使用numpy加速筛选
	timestamps = df['timestamp_int'].values
	indices = np.arange(len(df))
	
	for current_start in range(min_time, max_time - window_size_sec + 1, step_size_sec):
		mask = (timestamps >= current_start) & (timestamps < current_start + window_size_sec)
		window_indices = indices[mask]
		if len(window_indices) > 0:
			sliding_windows.append(df.iloc[window_indices])
	# 测试时间范围覆盖验证
	# for i, window in enumerate(sliding_windows[:3]):
	# 	start = pd.to_datetime(window['timestamp'].min(), unit='s')
	# 	end = pd.to_datetime(window['timestamp'].max(), unit='s')
	# 	print(f"窗口{i}: {start} ~ {end} 数据量:{len(window)}")
	return sliding_windows


def analysis(sliding_windows,specified_numbers):
	list_output_data = []
	# 遍历滑动窗口
	for window in sliding_windows:
		# 获取窗口中的金标心率值 默认使用第0个
		golden_heart_rate = window['金标心率'].tolist()[0]
		# 获取窗口中的时间戳
		timestamp = window['time'].tolist()
		
		#数据存储字典
		data_dict={}
		
		# 遍历 指定的rawData列
		for i in specified_numbers:
			name = f'rawData{i}'
			#print(f'{name} 开始计算 timestamp范围:{timestamp[0]}~{timestamp[-1]}')
			data_dict['时间节点']= f'{timestamp[0]}~{timestamp[-1]}'
			rawData_columns = window[f'rawData{i}']
			useAgcCurrent_columns = window[f'useAgcCurrent{i}']
			useAgcGain_columns = window[f'useAgcGain{i}']
			
			# 如果column_data中的数字全是0，则跳过该列
			if all(x == 0 for x in rawData_columns):
				print(f"{name} column_data中的数字全是0，跳过该列")
				continue
			
			# 处理时域数据判断
			result = is_cutting_back_clipping_mutation(name,rawData_columns)
			#把result所有键值添加到data_dict中
			for key, value in result.items():
				data_dict[key] = value
			# 进行频域计算
			now_sig_czt, now_sig_freq, max_peak_of_wave, some_peak_of_wave, energy_ratio_of_wave, peak_list, frequency_peaks_list, czt_values_list, ac_dc_energy = get_cztdata_process(
				window_data=rawData_columns.tolist(), fs=25, Gain_list=useAgcGain_columns.tolist(),
				now_polar_heartbeat=golden_heart_rate)
			
			data_dict[f'{name}-最大峰能量占比']=max_peak_of_wave
			data_dict[f'{name}-干扰峰个数']=some_peak_of_wave
			data_dict[f'{name}-算法峰能量占比']=energy_ratio_of_wave
			data_dict[f'{name}-AC/DC能量占比']=ac_dc_energy
			
			
		list_output_data.append(data_dict)


	return list_output_data
	
#导出数据
def export_data(df, output_file_path):
	# 导出数据
	dict_rt = {
		'截顶': '求占比',
		'截底': '求占比',
		'突变': '求占比',
		'算法峰能量占比': '求均值',
		'AC/DC能量占比': '求均值',
		'最大峰能量占比': '求均值',
		'干扰峰个数': '求均值'
	}
	output_df = pd.DataFrame(df)
	# 重命名列，将 'rawData' 中的小写 'r' 替换为大写 'R'
	output_df.columns = output_df.columns.str.replace('rawData', 'RawData')
	
	# 处理列
	processed_data = {}
	for key, method in dict_rt.items():
		# 找到所有包含 key 的列
		matching_columns = [col for col in output_df.columns if key in col]
		for col in matching_columns:
			if method == '求占比':
				count_ones = (output_df[col] == 1).sum()
				total_count = len(output_df[col])
				processed_data[f'{col}'] = count_ones / total_count if total_count > 0 else 0
			elif method == '求均值':
				processed_data[f'{col}'] = output_df[col].mean()
	
	# 将处理结果添加到 output_df 的最后一行
	processed_df = pd.DataFrame([processed_data])
	output_df = pd.concat([output_df, processed_df], ignore_index=True)
	
	output_df.to_excel(output_file_path, index=False)

def is_cutting_back_clipping_mutation(name,rawData_columns):
	"""
	判断给定的数据列是否出现截顶、截底和突变。
	如果已判断为截顶或截底状态时，不判断突变。
	:param rawData_columns: 一个包含原始数据的列表或数组。
	:return: 一个字典，包含是否出现截顶、截底和突变的结果。
	"""
	# 获取rawData_columns中的最大值和最小值
	max_value = max(rawData_columns)
	min_value = min(rawData_columns)
	
	# 初始化结果字典
	result = {
		f'{name}-截顶': 0,
		f'{name}-截底': 0,
		f'{name}-突变': 0
	}
	
	# 判断是否截顶
	if max_value > 16000000 or (max_value > 15000000 and (max_value - min_value) > 1000000):
		result[f'{name}-截顶'] = 1
		
	
	# 判断是否截底
	if min_value < 9500000:
		result[f'{name}-截底'] = 1
	
	# 判断是否突变
	if not (result[f'{name}-截顶'] or result[f'{name}-截底']):
		if max_value - min_value > 10000000:
			result[f'{name}-突变'] = 1
	
	return result

#单文件分析
def analysis_file(file):
	
	# 筛选指定的列,只获取指定的rawData列
	specified_numbers = [4, 7, 13, 14, 20, 21, 22, 23, 25, 26, 28, 29, 30, 31]
	rawData_df = read_xlsx_file(file)
	sliding_windows = analysis_data(rawData_df)
	list_output_data=analysis(sliding_windows, specified_numbers)
	#获取file目录,再创建一个子目录
	file_dir = os.path.dirname(file)
	output_dir = os.path.join(file_dir, '频域分析后')
	if not os.path.exists(output_dir):
		os.makedirs(output_dir)
	#获获取file文件名
	file_name = os.path.splitext(os.path.basename(file))[0]
	output_file_path = os.path.join(output_dir, f'{file_name}_频域分析后.xlsx')
	export_data(list_output_data, output_file_path)


def analysis_dir(dir):
	file_paths = []
	# 遍历指定目录下的直接子项（不递归子目录）
	for entry in os.listdir(dir):
		# 拼接完整路径
		full_path = os.path.join(dir, entry)
		# 检查是否为文件且以 .xlsx 结尾
		if os.path.isfile(full_path) and entry.endswith('.xlsx'):
			file_paths.append(full_path)
	
	# 使用多进程处理文件
	
	with multiprocessing.Pool(processes=os.cpu_count()) as pool:
		pool.map(analysis_file, file_paths)


if __name__ == '__main__':
	# 记录开始时间
	start_time = time.time()
	file=r'静息_紧佩戴_6_02120949_rxfhdlkuhnsbgnml.xlsx'
	#analysis_file(file)
	dirs = '平台测试'
	analysis_dir(dirs)
	
	# 记录结束时间
	end_time = time.time()
	
	# 计算并打印运行时间
	print(f"运行时间: {end_time - start_time} 秒")